Migrate from rustc-serialize to Serde
authorAlex Crichton <alex@alexcrichton.com>
Fri, 10 Feb 2017 20:01:52 +0000 (12:01 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 22 Feb 2017 18:29:40 +0000 (10:29 -0800)
This commit migrates Cargo as much as possible from rustc-serialize to
Serde. This not only provides an excellent testing ground for the toml
0.3 release but it also is a big boost to the speed of parsing the JSON
bits of the registry.

This doesn't completely excise the dependency just yet as docopt still
requires it along with handlebars. I'm sure though that in time those
crates will migrate to serde!

35 files changed:
Cargo.lock
Cargo.toml
src/bin/cargo.rs
src/bin/locate_project.rs
src/bin/verify_project.rs
src/cargo/core/dependency.rs
src/cargo/core/manifest.rs
src/cargo/core/package.rs
src/cargo/core/package_id.rs
src/cargo/core/resolver/encode.rs
src/cargo/core/source.rs
src/cargo/lib.rs
src/cargo/ops/cargo_install.rs
src/cargo/ops/cargo_output_metadata.rs
src/cargo/ops/cargo_rustc/fingerprint.rs
src/cargo/ops/cargo_rustc/mod.rs
src/cargo/ops/lockfile.rs
src/cargo/sources/directory.rs
src/cargo/sources/git/utils.rs
src/cargo/sources/registry/index.rs
src/cargo/sources/registry/mod.rs
src/cargo/sources/registry/remote.rs
src/cargo/util/config.rs
src/cargo/util/errors.rs
src/cargo/util/machine_message.rs
src/cargo/util/toml.rs
src/crates-io/Cargo.toml
src/crates-io/lib.rs
tests/bad-config.rs
tests/build.rs
tests/cargotest/Cargo.toml
tests/cargotest/lib.rs
tests/cargotest/support/mod.rs
tests/cargotest/support/registry.rs
tests/registry.rs

index 8617962f3f961a98eaa065b8e6ba7d605c52d5e8..e51ec1605f02331c703adb8b1c254bbe4935bc24 100644 (file)
@@ -28,11 +28,15 @@ dependencies = [
  "psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
  "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_ignored 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -86,6 +90,8 @@ dependencies = [
  "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -111,7 +117,9 @@ name = "crates-io"
 version = "0.7.0"
 dependencies = [
  "curl 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -156,6 +164,11 @@ dependencies = [
  "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "dtoa"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "env_logger"
 version = "0.4.0"
@@ -272,6 +285,11 @@ dependencies = [
  "unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "itoa"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "kernel32-sys"
 version = "0.2.2"
@@ -521,6 +539,11 @@ name = "quick-error"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "quote"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "rand"
 version = "0.3.15"
@@ -581,6 +604,48 @@ name = "semver-parser"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "serde"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "serde_codegen_internals"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "syn 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_derive"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "quote 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_codegen_internals 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_ignored"
+version = "0.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_json"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "shell-escape"
 version = "0.1.3"
@@ -591,6 +656,15 @@ name = "strsim"
 version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "syn"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "quote 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "tar"
 version = "0.4.10"
@@ -656,8 +730,13 @@ dependencies = [
 name = "toml"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "toml"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -673,6 +752,11 @@ name = "unicode-normalization"
 version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "unicode-xid"
+version = "0.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "unreachable"
 version = "0.1.1"
@@ -745,6 +829,7 @@ dependencies = [
 "checksum curl 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "654c5b772f9e62a46a99cc9ee7442e80a139027889a6305cdd59bc1e5eb3e3e8"
 "checksum curl-sys 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "a89415561199ca2ac6de2519674739159c1583bc0a9b46ec30fd3814999d5ef5"
 "checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8"
+"checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90"
 "checksum env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "99971fb1b635fe7a0ee3c4d065845bb93cca80a23b5613b5613391ece5de4144"
 "checksum error-chain 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "318cb3c71ee4cdea69fdc9e15c173b245ed6063e1709029e8fd32525a881120f"
 "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
@@ -758,6 +843,7 @@ dependencies = [
 "checksum hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4"
 "checksum handlebars 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b930077f1422bf853008047b55896efc1409744bfc9903f1eec1a58fcc7edeff"
 "checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
+"checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
 "checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b"
 "checksum libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "684f330624d8c3784fb9558ca46c4ce488073a8d22450415c5eb4f4cfb0d11b5"
@@ -787,6 +873,7 @@ dependencies = [
 "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
 "checksum psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "abcd5d1a07d360e29727f757a9decb3ce8bc6e0efa8969cfaad669a8317a2478"
 "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c"
+"checksum quote 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "e7b44fd83db28b83c1c58187159934906e5e955c812e211df413b76b03c909a5"
 "checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
 "checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
 "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01"
@@ -795,8 +882,14 @@ dependencies = [
 "checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b"
 "checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
 "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+"checksum serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0ae9a3c8b07c09dbe43022486d55a18c629a0618d2241e49829aaef9b6d862f9"
+"checksum serde_codegen_internals 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c3172bf2940b975c0e4f6ab42a511c0a4407d4f46ccef87a9d3615db5c26fa96"
+"checksum serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ecc6e0379ca933ece58302d2d3034443f06fbf38fd535857c1dc516195cbc3bf"
+"checksum serde_ignored 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4b3f5576874721d14690657e9f0ed286e72a52be2f6fdc0cf2f024182bd8f64"
+"checksum serde_json 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e095e4e94e7382b76f48e93bd845ffddda62df8dfd4c163b1bfa93d40e22e13a"
 "checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8"
 "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
+"checksum syn 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f94368aae82bb29656c98443a7026ca931a659e8d19dcdc41d6e273054e820"
 "checksum tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "1eb3bf6ec92843ca93f4fcfb5fc6dfe30534815b147885db4b5759b8e2ff7d52"
 "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
 "checksum term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3deff8a2b3b6607d6d7cc32ac25c0b33709453ca9cceac006caac51e963cf94a"
@@ -805,8 +898,10 @@ dependencies = [
 "checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
 "checksum thread_local 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7793b722f0f77ce716e7f1acf416359ca32ff24d04ffbac4269f44a4a83be05d"
 "checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4"
+"checksum toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08272367dd2e766db3fa38f068067d17aa6a9dfd7259af24b3927db92f1e0c2f"
 "checksum unicode-bidi 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b61814f3e7fd0e0f15370f767c7c943e08bc2e3214233ae8f88522b334ceb778"
 "checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff"
+"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
 "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
 "checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e"
 "checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47"
index 99e0f1e6eff32364c49ce2ccb94312762bf5e470..d7120460b507a5d45bd04a95cc06eab10236a362 100644 (file)
@@ -35,11 +35,15 @@ log = "0.3"
 num_cpus = "1.0"
 rustc-serialize = "0.3"
 semver = "0.6.0"
+serde = "0.9"
+serde_derive = "0.9"
+serde_json = "0.9"
+serde_ignored = "0.0.2"
 shell-escape = "0.1"
 tar = { version = "0.4", default-features = false }
 tempdir = "0.3"
 term = "0.4.4"
-toml = "0.2"
+toml = "0.3"
 url = "1.1"
 
 [target.'cfg(unix)'.dependencies]
index 792c9002d1b6fbb907744a5c6f291eb2c6cade7a..0d0171ad2e8b1a5be85eaba0a3881682d78231f4 100644 (file)
@@ -6,6 +6,9 @@ extern crate rustc_serialize;
 extern crate toml;
 #[macro_use]
 extern crate log;
+#[macro_use]
+extern crate serde_derive;
+extern crate serde_json;
 
 use std::collections::BTreeSet;
 use std::collections::HashMap;
index d89f6526920eafd9b72ef6ee9e33c08355e01bd3..810be467c0a326b8912ed2135f38224d0ad1ea6a 100644 (file)
@@ -18,7 +18,7 @@ Options:
     -h, --help              Print this message
 ";
 
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 pub struct ProjectLocation {
     root: String
 }
index 882873d1f1e08b3a3cf17f837e5d3579232efe1a..26e11f96644ab5c87b540cffeb7f307f6f0c64e3 100644 (file)
@@ -6,7 +6,7 @@ use std::process;
 use cargo;
 use cargo::util::important_paths::{find_root_manifest_for_wd};
 use cargo::util::{CliResult, Config};
-use rustc_serialize::json;
+use serde_json;
 use toml;
 
 #[derive(RustcDecodable)]
@@ -55,10 +55,9 @@ pub fn execute(args: Flags, config: &Config) -> CliResult {
         Ok(_) => {},
         Err(e) => fail("invalid", &format!("error reading file: {}", e))
     };
-    match toml::Parser::new(&contents).parse() {
-        None => fail("invalid", "invalid-format"),
-        Some(..) => {}
-    };
+    if contents.parse::<toml::Value>().is_err() {
+        fail("invalid", "invalid-format");
+    }
 
     let mut h = HashMap::new();
     h.insert("success".to_string(), "true".to_string());
@@ -69,6 +68,6 @@ pub fn execute(args: Flags, config: &Config) -> CliResult {
 fn fail(reason: &str, value: &str) -> ! {
     let mut h = HashMap::new();
     h.insert(reason.to_string(), value.to_string());
-    println!("{}", json::encode(&h).unwrap());
+    println!("{}", serde_json::to_string(&h).unwrap());
     process::exit(1)
 }
index 377f21dee061c2355629aed191e6ecbaa57f1fec..9401eeccbb0a8f5b9dccd6d85f4c3462015e9dcf 100644 (file)
@@ -4,7 +4,7 @@ use std::str::FromStr;
 
 use semver::VersionReq;
 use semver::ReqParseError;
-use rustc_serialize::{Encoder, Encodable};
+use serde::ser;
 
 use core::{SourceId, Summary, PackageId};
 use util::{CargoError, CargoResult, Cfg, CfgExpr, ChainError, human, Config};
@@ -41,7 +41,7 @@ pub enum Platform {
     Cfg(CfgExpr),
 }
 
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 struct SerializedDependency<'a> {
     name: &'a str,
     source: &'a SourceId,
@@ -54,8 +54,10 @@ struct SerializedDependency<'a> {
     target: Option<&'a Platform>,
 }
 
-impl Encodable for Dependency {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl ser::Serialize for Dependency {
+    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
+        where S: ser::Serializer,
+    {
         SerializedDependency {
             name: self.name(),
             source: &self.source_id(),
@@ -65,7 +67,7 @@ impl Encodable for Dependency {
             uses_default_features: self.uses_default_features(),
             features: self.features(),
             target: self.platform(),
-        }.encode(s)
+        }.serialize(s)
     }
 }
 
@@ -76,13 +78,15 @@ pub enum Kind {
     Build,
 }
 
-impl Encodable for Kind {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl ser::Serialize for Kind {
+    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
+        where S: ser::Serializer,
+    {
         match *self {
             Kind::Normal => None,
             Kind::Development => Some("dev"),
             Kind::Build => Some("build"),
-        }.encode(s)
+        }.serialize(s)
     }
 }
 
@@ -136,7 +140,7 @@ This will soon become a hard error, so it's either recommended to
 update to a fixed version or contact the upstream maintainer about
 this warning.
 ",
-       req, inside.name(), inside.version(), requirement);
+    req, inside.name(), inside.version(), requirement);
                         config.shell().warn(&msg)?;
 
                         Ok(requirement)
@@ -348,9 +352,11 @@ impl Platform {
     }
 }
 
-impl Encodable for Platform {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        self.to_string().encode(s)
+impl ser::Serialize for Platform {
+    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
+        where S: ser::Serializer,
+    {
+        self.to_string().serialize(s)
     }
 }
 
index 4ab5ea4f9f1801c1181170259d6d43c1546f84da..24cfd4d42f4367e9d4f9806330dd0c63c8ddd377 100644 (file)
@@ -3,7 +3,7 @@ use std::fmt;
 use std::path::{PathBuf, Path};
 
 use semver::Version;
-use rustc_serialize::{Encoder, Encodable};
+use serde::ser;
 
 use core::{Dependency, PackageId, Summary, SourceId, PackageIdSpec};
 use core::WorkspaceConfig;
@@ -113,72 +113,68 @@ pub enum TargetKind {
 }
 
 impl TargetKind {
-    /// Returns a vector of crate types as specified in a manifest with one difference.
-    /// For ExampleLib it returns "example" instead of crate types
-    pub fn kinds(&self) -> Vec<&str> {
+    /// Returns a vector of crate types as specified in a manifest
+    pub fn crate_types(&self) -> Vec<&str> {
         use self::TargetKind::*;
         match *self {
-            Lib(ref kinds) => kinds.iter().map(LibKind::crate_type).collect(),
+            Lib(ref kinds) | ExampleLib(ref kinds) => {
+                kinds.iter().map(LibKind::crate_type).collect()
+            }
             Bin => vec!["bin"],
-            ExampleBin | ExampleLib(_) => vec!["example"],
+            ExampleBin => vec!["example"],
             Test => vec!["test"],
             CustomBuild => vec!["custom-build"],
             Bench => vec!["bench"]
         }
     }
+}
 
-    /// Returns a vector of crate types as specified in a manifest
-    pub fn crate_types(&self) -> Vec<&str> {
+impl ser::Serialize for TargetKind {
+    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
+        where S: ser::Serializer,
+    {
         use self::TargetKind::*;
         match *self {
-            Lib(ref kinds) | ExampleLib(ref kinds) => {
-                kinds.iter().map(LibKind::crate_type).collect()
-            }
+            Lib(ref kinds) => kinds.iter().map(LibKind::crate_type).collect(),
             Bin => vec!["bin"],
-            ExampleBin => vec!["example"],
+            ExampleBin | ExampleLib(_) => vec!["example"],
             Test => vec!["test"],
             CustomBuild => vec!["custom-build"],
             Bench => vec!["bench"]
-        }
+        }.serialize(s)
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+
+// Note that most of the fields here are skipped when serializing because we
+// don't want to export them just yet (becomes a public API of Cargo). Others
+// though are definitely needed!
+#[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize)]
 pub struct Profile {
     pub opt_level: String,
+    #[serde(skip_serializing)]
     pub lto: bool,
+    #[serde(skip_serializing)]
     pub codegen_units: Option<u32>,    // None = use rustc default
+    #[serde(skip_serializing)]
     pub rustc_args: Option<Vec<String>>,
+    #[serde(skip_serializing)]
     pub rustdoc_args: Option<Vec<String>>,
     pub debuginfo: Option<u32>,
     pub debug_assertions: bool,
+    #[serde(skip_serializing)]
     pub rpath: bool,
     pub test: bool,
+    #[serde(skip_serializing)]
     pub doc: bool,
+    #[serde(skip_serializing)]
     pub run_custom_build: bool,
+    #[serde(skip_serializing)]
     pub check: bool,
+    #[serde(skip_serializing)]
     pub panic: Option<String>,
 }
 
-#[derive(RustcEncodable)]
-struct SerializedProfile<'a> {
-    opt_level: &'a str,
-    debuginfo: Option<u32>,
-    debug_assertions: bool,
-    test: bool,
-}
-
-impl Encodable for Profile {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        SerializedProfile {
-            opt_level: &self.opt_level,
-            debuginfo: self.debuginfo,
-            debug_assertions: self.debug_assertions,
-            test: self.test,
-        }.encode(s)
-    }
-}
-
 #[derive(Default, Clone, Debug, PartialEq, Eq)]
 pub struct Profiles {
     pub release: Profile,
@@ -209,22 +205,22 @@ pub struct Target {
     for_host: bool,
 }
 
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 struct SerializedTarget<'a> {
-    kind: Vec<&'a str>,
+    kind: &'a TargetKind,
     crate_types: Vec<&'a str>,
     name: &'a str,
-    src_path: &'a str,
+    src_path: &'a PathBuf,
 }
 
-impl Encodable for Target {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl ser::Serialize for Target {
+    fn serialize<S: ser::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
         SerializedTarget {
-            kind: self.kind.kinds(),
+            kind: &self.kind,
             crate_types: self.kind.crate_types(),
             name: &self.name,
-            src_path: &self.src_path.display().to_string(),
-        }.encode(s)
+            src_path: &self.src_path,
+        }.serialize(s)
     }
 }
 
index 6b4cd2835d95e7131d493ccc1142017073d24401..898745460f98abc08560af0b534dd779ea72c567 100644 (file)
@@ -5,12 +5,12 @@ use std::hash;
 use std::path::{Path, PathBuf};
 
 use semver::Version;
+use serde::ser;
 
 use core::{Dependency, Manifest, PackageId, SourceId, Target};
 use core::{Summary, SourceMap};
 use ops;
 use util::{CargoResult, Config, LazyCell, ChainError, internal, human, lev_distance};
-use rustc_serialize::{Encoder,Encodable};
 
 /// Information about a package that is available somewhere in the file system.
 ///
@@ -24,7 +24,7 @@ pub struct Package {
     manifest_path: PathBuf,
 }
 
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 struct SerializedPackage<'a> {
     name: &'a str,
     version: &'a str,
@@ -39,8 +39,10 @@ struct SerializedPackage<'a> {
     manifest_path: &'a str,
 }
 
-impl Encodable for Package {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl ser::Serialize for Package {
+    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
+        where S: ser::Serializer,
+    {
         let summary = self.manifest.summary();
         let package_id = summary.package_id();
         let manmeta = self.manifest.metadata();
@@ -60,7 +62,7 @@ impl Encodable for Package {
             targets: &self.manifest.targets(),
             features: summary.features(),
             manifest_path: &self.manifest_path.display().to_string(),
-        }.encode(s)
+        }.serialize(s)
     }
 }
 
index 12e6fae78ffd196d443d7cb3433e7469c1229cf7..e2bd95c081a3cda191abe4cbc0f5df89958d82c5 100644 (file)
@@ -5,8 +5,9 @@ use std::hash::Hash;
 use std::hash;
 use std::sync::Arc;
 
-use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
 use semver;
+use serde::de;
+use serde::ser;
 
 use util::{CargoResult, CargoError, ToSemver};
 use core::source::SourceId;
@@ -24,40 +25,41 @@ struct PackageIdInner {
     source_id: SourceId,
 }
 
-impl Encodable for PackageId {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl ser::Serialize for PackageId {
+    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
+        where S: ser::Serializer
+    {
         let source = self.inner.source_id.to_url();
         let encoded = format!("{} {} ({})", self.inner.name, self.inner.version,
                               source);
-        encoded.encode(s)
+        encoded.serialize(s)
     }
 }
 
-impl Decodable for PackageId {
-    fn decode<D: Decoder>(d: &mut D) -> Result<PackageId, D::Error> {
-        let string: String = Decodable::decode(d)?;
+impl de::Deserialize for PackageId {
+    fn deserialize<D>(d: D) -> Result<PackageId, D::Error>
+        where D: de::Deserializer
+    {
+        let string = String::deserialize(d)?;
         let mut s = string.splitn(3, ' ');
         let name = s.next().unwrap();
         let version = match s.next() {
             Some(s) => s,
-            None => return Err(d.error("invalid serialized PackageId")),
+            None => return Err(de::Error::custom("invalid serialized PackageId")),
         };
-        let version = semver::Version::parse(version).map_err(|_| {
-            d.error("invalid version")
-        })?;
+        let version = semver::Version::parse(version)
+                            .map_err(de::Error::custom)?;
         let url = match s.next() {
             Some(s) => s,
-            None => return Err(d.error("invalid serialized PackageId")),
+            None => return Err(de::Error::custom("invalid serialized PackageId")),
         };
         let url = if url.starts_with("(") && url.ends_with(")") {
             &url[1..url.len() - 1]
         } else {
-            return Err(d.error("invalid serialized PackageId"))
+            return Err(de::Error::custom("invalid serialized PackageId"))
 
         };
-        let source_id = SourceId::from_url(url).map_err(|e| {
-            d.error(&e.to_string())
-        })?;
+        let source_id = SourceId::from_url(url).map_err(de::Error::custom)?;
 
         Ok(PackageId {
             inner: Arc::new(PackageIdInner {
index 1971801bcabcd15a63843c1dad9b72eb52fd625c..801fc474084ec461c633e758a82db4a8d322d43e 100644 (file)
@@ -2,14 +2,15 @@ use std::collections::{HashMap, HashSet, BTreeMap};
 use std::fmt;
 use std::str::FromStr;
 
-use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
+use serde::ser;
+use serde::de;
 
 use core::{Package, PackageId, SourceId, Workspace};
 use util::{CargoResult, Graph, Config, internal, ChainError, CargoError};
 
 use super::Resolve;
 
-#[derive(RustcEncodable, RustcDecodable, Debug)]
+#[derive(Serialize, Deserialize, Debug)]
 pub struct EncodableResolve {
     package: Option<Vec<EncodableDependency>>,
     /// `root` is optional to allow forward compatibility.
@@ -206,7 +207,7 @@ fn build_path_deps(ws: &Workspace) -> HashMap<String, SourceId> {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable, Debug, PartialOrd, Ord, PartialEq, Eq)]
+#[derive(Serialize, Deserialize, Debug, PartialOrd, Ord, PartialEq, Eq)]
 pub struct EncodableDependency {
     name: String,
     version: String,
@@ -260,17 +261,21 @@ impl FromStr for EncodablePackageId {
     }
 }
 
-impl Encodable for EncodablePackageId {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        self.to_string().encode(s)
+impl ser::Serialize for EncodablePackageId {
+    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
+        where S: ser::Serializer,
+    {
+        self.to_string().serialize(s)
     }
 }
 
-impl Decodable for EncodablePackageId {
-    fn decode<D: Decoder>(d: &mut D) -> Result<EncodablePackageId, D::Error> {
-        String::decode(d).and_then(|string| {
+impl de::Deserialize for EncodablePackageId {
+    fn deserialize<D>(d: D) -> Result<EncodablePackageId, D::Error>
+        where D: de::Deserializer,
+    {
+        String::deserialize(d).and_then(|string| {
             string.parse::<EncodablePackageId>()
-                  .map_err(|e| d.error(&e.to_string()))
+                  .map_err(de::Error::custom)
         })
     }
 }
@@ -281,8 +286,10 @@ pub struct WorkspaceResolve<'a, 'cfg: 'a> {
     pub use_root_key: bool,
 }
 
-impl<'a, 'cfg> Encodable for WorkspaceResolve<'a, 'cfg> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<'a, 'cfg> ser::Serialize for WorkspaceResolve<'a, 'cfg> {
+    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
+        where S: ser::Serializer,
+    {
         let mut ids: Vec<&PackageId> = self.resolve.graph.iter().collect();
         ids.sort();
 
@@ -320,7 +327,7 @@ impl<'a, 'cfg> Encodable for WorkspaceResolve<'a, 'cfg> {
             package: Some(encodable),
             root: root,
             metadata: metadata,
-        }.encode(s)
+        }.serialize(s)
     }
 }
 
index dc334535f73dd6b065f29ce8f4562278817018fd..142adfdb69dfdab4b84663654fdf368c6b2fdfc0 100644 (file)
@@ -7,7 +7,8 @@ use std::sync::Arc;
 use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
 use std::sync::atomic::Ordering::SeqCst;
 
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use serde::ser;
+use serde::de;
 use url::Url;
 
 use core::{Package, PackageId, Registry};
@@ -342,22 +343,24 @@ impl Ord for SourceId {
     }
 }
 
-impl Encodable for SourceId {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl ser::Serialize for SourceId {
+    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
+        where S: ser::Serializer,
+    {
         if self.is_path() {
-            s.emit_option_none()
+            None::<String>.serialize(s)
         } else {
-            self.to_url().encode(s)
+            Some(self.to_url()).serialize(s)
         }
     }
 }
 
-impl Decodable for SourceId {
-    fn decode<D: Decoder>(d: &mut D) -> Result<SourceId, D::Error> {
-        let string: String = Decodable::decode(d)?;
-        SourceId::from_url(&string).map_err(|e| {
-            d.error(&e.to_string())
-        })
+impl de::Deserialize for SourceId {
+    fn deserialize<D>(d: D) -> Result<SourceId, D::Error>
+        where D: de::Deserializer,
+    {
+        let string = String::deserialize(d)?;
+        SourceId::from_url(&string).map_err(de::Error::custom)
     }
 }
 
index f63cd57cd5cccab2bdcc465019d5e73eac187cfc..a844359e746747572bd16fc5d22596310a35960c 100755 (executable)
@@ -3,6 +3,8 @@
 
 #[cfg(test)] extern crate hamcrest;
 #[macro_use] extern crate log;
+#[macro_use] extern crate serde_derive;
+#[macro_use] extern crate serde_json;
 extern crate crates_io as registry;
 extern crate crossbeam;
 extern crate curl;
@@ -18,6 +20,8 @@ extern crate libgit2_sys;
 extern crate num_cpus;
 extern crate rustc_serialize;
 extern crate semver;
+extern crate serde;
+extern crate serde_ignored;
 extern crate shell_escape;
 extern crate tar;
 extern crate tempdir;
@@ -27,8 +31,8 @@ extern crate url;
 
 use std::io;
 use std::fmt;
-use rustc_serialize::{Decodable, Encodable};
-use rustc_serialize::json;
+use rustc_serialize::Decodable;
+use serde::ser;
 use docopt::Docopt;
 
 use core::{Shell, MultiShell, ShellConfig, Verbosity, ColorConfig};
@@ -121,8 +125,8 @@ pub fn call_main_without_stdin<Flags: Decodable>(
     exec(flags, config)
 }
 
-pub fn print_json<T: Encodable>(obj: &T) {
-    let encoded = json::encode(&obj).unwrap();
+pub fn print_json<T: ser::Serialize>(obj: &T) {
+    let encoded = serde_json::to_string(&obj).unwrap();
     println!("{}", encoded);
 }
 
index 02daac2ab6ddbec72463cf75ac5f2fc8086b58ab..5ad84e376ff5125df637e5f1a46e6f6d84f521b5 100644 (file)
@@ -19,13 +19,18 @@ use sources::{GitSource, PathSource, SourceConfigMap};
 use util::{CargoResult, ChainError, Config, human, internal};
 use util::{Filesystem, FileLock};
 
-#[derive(RustcDecodable, RustcEncodable)]
+#[derive(Deserialize, Serialize)]
+#[serde(untagged)]
 enum CrateListing {
     V1(CrateListingV1),
-    Empty,
+    Empty(Empty),
 }
 
-#[derive(RustcDecodable, RustcEncodable)]
+#[derive(Deserialize, Serialize)]
+#[serde(deny_unknown_fields)]
+struct Empty {}
+
+#[derive(Deserialize, Serialize)]
 struct CrateListingV1 {
     v1: BTreeMap<PackageId, BTreeSet<String>>,
 }
@@ -412,12 +417,12 @@ fn read_crate_list(mut file: &File) -> CargoResult<CrateListingV1> {
     (|| -> CargoResult<_> {
         let mut contents = String::new();
         file.read_to_string(&mut contents)?;
-        let listing = toml::decode_str(&contents).chain_error(|| {
+        let listing = toml::from_str(&contents).chain_error(|| {
             internal("invalid TOML found for metadata")
         })?;
         match listing {
             CrateListing::V1(v1) => Ok(v1),
-            CrateListing::Empty => {
+            CrateListing::Empty(_) => {
                 Ok(CrateListingV1 { v1: BTreeMap::new() })
             }
         }
@@ -430,7 +435,7 @@ fn write_crate_list(mut file: &File, listing: CrateListingV1) -> CargoResult<()>
     (|| -> CargoResult<_> {
         file.seek(SeekFrom::Start(0))?;
         file.set_len(0)?;
-        let data = toml::encode_str::<CrateListing>(&CrateListing::V1(listing));
+        let data = toml::to_string(&CrateListing::V1(listing))?;
         file.write_all(data.as_bytes())?;
         Ok(())
     }).chain_error(|| {
index e86a4de41896312d9653d76d10a79bf98881006f..bd48cb0a4b9150906202fa1597d843afe04157be 100644 (file)
@@ -1,4 +1,4 @@
-use rustc_serialize::{Encodable, Encoder};
+use serde::ser::{self, Serialize};
 
 use core::resolver::Resolve;
 use core::{Package, PackageId, Workspace};
@@ -67,7 +67,7 @@ fn metadata_full(ws: &Workspace,
     })
 }
 
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 pub struct ExportInfo {
     packages: Vec<Package>,
     workspace_members: Vec<PackageId>,
@@ -75,38 +75,29 @@ pub struct ExportInfo {
     version: u32,
 }
 
-/// Newtype wrapper to provide a custom `Encodable` implementation.
+/// Newtype wrapper to provide a custom `Serialize` implementation.
 /// The one from lockfile does not fit because it uses a non-standard
 /// format for `PackageId`s
-struct MetadataResolve{
+#[derive(Serialize)]
+struct MetadataResolve {
+    #[serde(rename = "nodes", serialize_with = "serialize_resolve")]
     resolve: Resolve,
     root: Option<PackageId>,
 }
 
-impl Encodable for MetadataResolve {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        #[derive(RustcEncodable)]
-        struct EncodableResolve<'a> {
-            root: Option<&'a PackageId>,
-            nodes: Vec<Node<'a>>,
-        }
+fn serialize_resolve<S>(resolve: &Resolve, s: S) -> Result<S::Ok, S::Error>
+    where S: ser::Serializer,
+{
+    #[derive(Serialize)]
+    struct Node<'a> {
+        id: &'a PackageId,
+        dependencies: Vec<&'a PackageId>,
+    }
 
-        #[derive(RustcEncodable)]
-        struct Node<'a> {
-            id: &'a PackageId,
-            dependencies: Vec<&'a PackageId>,
+    resolve.iter().map(|id| {
+        Node {
+            id: id,
+            dependencies: resolve.deps(id).collect(),
         }
-
-        let encodable = EncodableResolve {
-            root: self.root.as_ref(),
-            nodes: self.resolve.iter().map(|id| {
-                Node {
-                    id: id,
-                    dependencies: self.resolve.deps(id).collect(),
-                }
-            }).collect(),
-        };
-
-        encodable.encode(s)
-    }
+    }).collect::<Vec<_>>().serialize(s)
 }
index 9ada0fb748d091df83646ff8e98d89203a74d77f..a3af64f45706b766f1ad7f8c7e46bea756fa911d 100644 (file)
@@ -6,7 +6,9 @@ use std::path::{Path, PathBuf};
 use std::sync::{Arc, Mutex};
 
 use filetime::FileTime;
-use rustc_serialize::{json, Encodable, Decodable, Encoder, Decoder};
+use serde::ser::{self, Serialize};
+use serde::de::{self, Deserialize};
+use serde_json;
 
 use core::{Package, TargetKind};
 use util;
@@ -125,18 +127,48 @@ pub fn prepare_target<'a, 'cfg>(cx: &mut Context<'a, 'cfg>,
 /// `DependencyQueue`, but it also needs to be retained here because Cargo can
 /// be interrupted while executing, losing the state of the `DependencyQueue`
 /// graph.
+#[derive(Serialize, Deserialize)]
 pub struct Fingerprint {
     rustc: u64,
     features: String,
     target: u64,
     profile: u64,
+    #[serde(serialize_with = "serialize_deps", deserialize_with = "deserialize_deps")]
     deps: Vec<(String, Arc<Fingerprint>)>,
     local: LocalFingerprint,
+    #[serde(skip_serializing, skip_deserializing)]
     memoized_hash: Mutex<Option<u64>>,
     rustflags: Vec<String>,
 }
 
-#[derive(RustcEncodable, RustcDecodable, Hash)]
+fn serialize_deps<S>(deps: &Vec<(String, Arc<Fingerprint>)>, ser: S)
+                     -> Result<S::Ok, S::Error>
+    where S: ser::Serializer,
+{
+    deps.iter().map(|&(ref a, ref b)| {
+        (a, b.hash())
+    }).collect::<Vec<_>>().serialize(ser)
+}
+
+fn deserialize_deps<D>(d: D) -> Result<Vec<(String, Arc<Fingerprint>)>, D::Error>
+    where D: de::Deserializer,
+{
+    let decoded = <Vec<(String, u64)>>::deserialize(d)?;
+    Ok(decoded.into_iter().map(|(name, hash)| {
+        (name, Arc::new(Fingerprint {
+            rustc: 0,
+            target: 0,
+            profile: 0,
+            local: LocalFingerprint::Precalculated(String::new()),
+            features: String::new(),
+            deps: Vec::new(),
+            memoized_hash: Mutex::new(Some(hash)),
+            rustflags: Vec::new(),
+        }))
+    }).collect())
+}
+
+#[derive(Serialize, Deserialize, Hash)]
 enum LocalFingerprint {
     Precalculated(String),
     MtimeBased(MtimeSlot, PathBuf),
@@ -242,79 +274,27 @@ impl hash::Hash for Fingerprint {
     }
 }
 
-impl Encodable for Fingerprint {
-    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
-        e.emit_struct("Fingerprint", 6, |e| {
-            e.emit_struct_field("rustc", 0, |e| self.rustc.encode(e))?;
-            e.emit_struct_field("target", 1, |e| self.target.encode(e))?;
-            e.emit_struct_field("profile", 2, |e| self.profile.encode(e))?;
-            e.emit_struct_field("local", 3, |e| self.local.encode(e))?;
-            e.emit_struct_field("features", 4, |e| {
-                self.features.encode(e)
-            })?;
-            e.emit_struct_field("deps", 5, |e| {
-                self.deps.iter().map(|&(ref a, ref b)| {
-                    (a, b.hash())
-                }).collect::<Vec<_>>().encode(e)
-            })?;
-            e.emit_struct_field("rustflags", 6, |e| self.rustflags.encode(e))?;
-            Ok(())
-        })
-    }
-}
-
-impl Decodable for Fingerprint {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Fingerprint, D::Error> {
-        fn decode<T: Decodable, D: Decoder>(d: &mut D) -> Result<T, D::Error> {
-            Decodable::decode(d)
-        }
-        d.read_struct("Fingerprint", 6, |d| {
-            Ok(Fingerprint {
-                rustc: d.read_struct_field("rustc", 0, decode)?,
-                target: d.read_struct_field("target", 1, decode)?,
-                profile: d.read_struct_field("profile", 2, decode)?,
-                local: d.read_struct_field("local", 3, decode)?,
-                features: d.read_struct_field("features", 4, decode)?,
-                memoized_hash: Mutex::new(None),
-                deps: {
-                    let decode = decode::<Vec<(String, u64)>, D>;
-                    let v = d.read_struct_field("deps", 5, decode)?;
-                    v.into_iter().map(|(name, hash)| {
-                        (name, Arc::new(Fingerprint {
-                            rustc: 0,
-                            target: 0,
-                            profile: 0,
-                            local: LocalFingerprint::Precalculated(String::new()),
-                            features: String::new(),
-                            deps: Vec::new(),
-                            memoized_hash: Mutex::new(Some(hash)),
-                            rustflags: Vec::new(),
-                        }))
-                    }).collect()
-                },
-                rustflags: d.read_struct_field("rustflags", 6, decode)?,
-            })
-        })
-    }
-}
-
 impl hash::Hash for MtimeSlot {
     fn hash<H: Hasher>(&self, h: &mut H) {
         self.0.lock().unwrap().hash(h)
     }
 }
 
-impl Encodable for MtimeSlot {
-    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
+impl ser::Serialize for MtimeSlot {
+    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
+        where S: ser::Serializer,
+    {
         self.0.lock().unwrap().map(|ft| {
             (ft.seconds_relative_to_1970(), ft.nanoseconds())
-        }).encode(e)
+        }).serialize(s)
     }
 }
 
-impl Decodable for MtimeSlot {
-    fn decode<D: Decoder>(e: &mut D) -> Result<MtimeSlot, D::Error> {
-        let kind: Option<(u64, u32)> = Decodable::decode(e)?;
+impl de::Deserialize for MtimeSlot {
+    fn deserialize<D>(d: D) -> Result<MtimeSlot, D::Error>
+        where D: de::Deserializer,
+    {
+        let kind: Option<(u64, u32)> = de::Deserialize::deserialize(d)?;
         Ok(MtimeSlot(Mutex::new(kind.map(|(s, n)| {
             FileTime::from_seconds_since_1970(s, n)
         }))))
@@ -507,7 +487,7 @@ fn write_fingerprint(loc: &Path, fingerprint: &Fingerprint) -> CargoResult<()> {
     debug!("write fingerprint: {}", loc.display());
     paths::write(&loc, util::to_hex(hash).as_bytes())?;
     paths::write(&loc.with_extension("json"),
-                 json::encode(&fingerprint).unwrap().as_bytes())?;
+                 &serde_json::to_vec(&fingerprint).unwrap())?;
     Ok(())
 }
 
@@ -536,7 +516,7 @@ fn compare_old_fingerprint(loc: &Path, new_fingerprint: &Fingerprint)
     }
 
     let old_fingerprint_json = paths::read(&loc.with_extension("json"))?;
-    let old_fingerprint = json::decode(&old_fingerprint_json).chain_error(|| {
+    let old_fingerprint = serde_json::from_str(&old_fingerprint_json).chain_error(|| {
         internal(format!("failed to deserialize json"))
     })?;
     new_fingerprint.compare(&old_fingerprint)
index a8cfa13b72da10e4e0aff7481ba9ccb601d6c6c2..b8d6f07d2c3ffb6be8427ed5d4ed729241f4ff7f 100644 (file)
@@ -6,7 +6,7 @@ use std::io::{self, Write};
 use std::path::{self, PathBuf};
 use std::sync::Arc;
 
-use rustc_serialize::json;
+use serde_json;
 
 use core::{Package, PackageId, PackageSet, Target, Resolve};
 use core::{Profile, Profiles, Workspace};
@@ -346,7 +346,7 @@ fn rustc(cx: &mut Context, unit: &Unit, exec: Arc<Executor>) -> CargoResult<Work
                     // stderr from rustc can have a mix of JSON and non-JSON output
                     if line.starts_with('{') {
                         // Handle JSON lines
-                        let compiler_message = json::Json::from_str(line).map_err(|_| {
+                        let compiler_message = serde_json::from_str(line).map_err(|_| {
                             internal(&format!("compiler produced invalid json: `{}`", line))
                         })?;
 
index 6b055dfbb400da459b7b0cb2eda66fa824ead63c..1271cf82d5d9cbb32935d2ffe2051ae1c6d329bb 100644 (file)
@@ -1,7 +1,6 @@
 use std::io::prelude::*;
 
-use rustc_serialize::{Encodable, Decodable};
-use toml::{self, Encoder, Value};
+use toml;
 
 use core::{Resolve, resolver, Workspace};
 use core::resolver::WorkspaceResolve;
@@ -22,10 +21,8 @@ pub fn load_pkg_lockfile(ws: &Workspace) -> CargoResult<Option<Resolve>> {
     })?;
 
     (|| {
-        let table = cargo_toml::parse(&s, f.path(), ws.config())?;
-        let table = toml::Value::Table(table);
-        let mut d = toml::Decoder::new(table);
-        let v: resolver::EncodableResolve = Decodable::decode(&mut d)?;
+        let resolve = cargo_toml::parse(&s, f.path(), ws.config())?;
+        let v: resolver::EncodableResolve = resolve.try_into()?;
         Ok(Some(v.into_resolve(ws)?))
     }).chain_error(|| {
         human(format!("failed to parse lock file at: {}", f.path().display()))
@@ -50,24 +47,23 @@ pub fn write_pkg_lockfile(ws: &Workspace, resolve: &Resolve) -> CargoResult<()>
         true
     };
 
-    let mut e = Encoder::new();
-    WorkspaceResolve {
+    let toml = toml::Value::try_from(WorkspaceResolve {
         ws: ws,
         resolve: resolve,
         use_root_key: use_root_key,
-    }.encode(&mut e).unwrap();
+    }).unwrap();
 
     let mut out = String::new();
 
     // Note that we do not use e.toml.to_string() as we want to control the
     // exact format the toml is in to ensure pretty diffs between updates to the
     // lockfile.
-    if let Some(root) = e.toml.get(&"root".to_string()) {
+    if let Some(root) = toml.get("root") {
         out.push_str("[root]\n");
         emit_package(root.as_table().unwrap(), &mut out);
     }
 
-    let deps = e.toml[&"package".to_string()].as_slice().unwrap();
+    let deps = toml["package"].as_array().unwrap();
     for dep in deps.iter() {
         let dep = dep.as_table().unwrap();
 
@@ -75,9 +71,9 @@ pub fn write_pkg_lockfile(ws: &Workspace, resolve: &Resolve) -> CargoResult<()>
         emit_package(dep, &mut out);
     }
 
-    if let Some(metadata) = e.toml.get(&"metadata".to_string()) {
+    if let Some(meta) = toml.get("metadata") {
         out.push_str("[metadata]\n");
-        out.push_str(&metadata.to_string());
+        out.push_str(&meta.to_string());
     }
 
     // If the lockfile contents haven't changed so don't rewrite it. This is
@@ -117,16 +113,16 @@ fn has_crlf_line_endings(s: &str) -> bool {
     }
 }
 
-fn emit_package(dep: &toml::Table, out: &mut String) {
-    out.push_str(&format!("name = {}\n", lookup(dep, "name")));
-    out.push_str(&format!("version = {}\n", lookup(dep, "version")));
+fn emit_package(dep: &toml::value::Table, out: &mut String) {
+    out.push_str(&format!("name = {}\n", &dep["name"]));
+    out.push_str(&format!("version = {}\n", &dep["version"]));
 
     if dep.contains_key("source") {
-        out.push_str(&format!("source = {}\n", lookup(dep, "source")));
+        out.push_str(&format!("source = {}\n", &dep["source"]));
     }
 
-    if let Some(s) = dep.get("dependencies") {
-        let slice = Value::as_slice(s).unwrap();
+    if let Some(ref s) = dep.get("dependencies") {
+        let slice = s.as_array().unwrap();
 
         if !slice.is_empty() {
             out.push_str("dependencies = [\n");
@@ -139,10 +135,6 @@ fn emit_package(dep: &toml::Table, out: &mut String) {
         }
         out.push_str("\n");
     } else if dep.contains_key("replace") {
-        out.push_str(&format!("replace = {}\n\n", lookup(dep, "replace")));
+        out.push_str(&format!("replace = {}\n\n", &dep["replace"]));
     }
 }
-
-fn lookup<'a>(table: &'a toml::Table, key: &str) -> &'a toml::Value {
-    table.get(key).expect(&format!("didn't find {}", key))
-}
index c55fc3669a7b5dce4ed31ad23067616acde15ab1..1cf8b27550bdc4cde0928680f45539747227a2b0 100644 (file)
@@ -5,7 +5,7 @@ use std::io::Read;
 use std::path::{Path, PathBuf};
 
 use rustc_serialize::hex::ToHex;
-use rustc_serialize::json;
+use serde_json;
 
 use core::{Package, PackageId, Summary, SourceId, Source, Dependency, Registry};
 use sources::PathSource;
@@ -19,7 +19,7 @@ pub struct DirectorySource<'cfg> {
     config: &'cfg Config,
 }
 
-#[derive(RustcDecodable)]
+#[derive(Deserialize)]
 struct Checksum {
     package: String,
     files: HashMap<String, String>,
@@ -93,7 +93,7 @@ impl<'cfg> Source for DirectorySource<'cfg> {
                               pkg.package_id().version()))
 
             })?;
-            let cksum: Checksum = json::decode(&cksum).chain_error(|| {
+            let cksum: Checksum = serde_json::from_str(&cksum).chain_error(|| {
                 human(format!("failed to decode `.cargo-checksum.json` of \
                                {} v{}",
                               pkg.package_id().name(),
index 877752cead4196e4e82117450378e63d5a2b6760..97c43118c34fb041069fc83a6c2ec56900bc048d 100644 (file)
@@ -3,9 +3,9 @@ use std::fmt;
 use std::fs::{self, File};
 use std::path::{Path, PathBuf};
 
-use rustc_serialize::{Encodable, Encoder};
-use url::Url;
 use git2::{self, ObjectType};
+use serde::ser::{self, Serialize};
+use url::Url;
 
 use core::GitReference;
 use util::{CargoResult, ChainError, human, ToUrl, internal, Config, network};
@@ -13,6 +13,19 @@ use util::{CargoResult, ChainError, human, ToUrl, internal, Config, network};
 #[derive(PartialEq, Clone, Debug)]
 pub struct GitRevision(git2::Oid);
 
+impl ser::Serialize for GitRevision {
+    fn serialize<S: ser::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
+        serialize_str(self, s)
+    }
+}
+
+fn serialize_str<T, S>(t: &T, s: S) -> Result<S::Ok, S::Error>
+    where T: fmt::Display,
+          S: ser::Serializer,
+{
+    t.to_string().serialize(s)
+}
+
 impl fmt::Display for GitRevision {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         fmt::Display::fmt(&self.0, f)
@@ -29,77 +42,34 @@ impl GitShortID {
 
 /// GitRemote represents a remote repository. It gets cloned into a local
 /// GitDatabase.
-#[derive(PartialEq,Clone,Debug)]
+#[derive(PartialEq, Clone, Debug, Serialize)]
 pub struct GitRemote {
+    #[serde(serialize_with = "serialize_str")]
     url: Url,
 }
 
-#[derive(PartialEq,Clone,RustcEncodable)]
-struct EncodableGitRemote {
-    url: String,
-}
-
-impl Encodable for GitRemote {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        EncodableGitRemote {
-            url: self.url.to_string()
-        }.encode(s)
-    }
-}
-
 /// GitDatabase is a local clone of a remote repository's database. Multiple
 /// GitCheckouts can be cloned from this GitDatabase.
+#[derive(Serialize)]
 pub struct GitDatabase {
     remote: GitRemote,
     path: PathBuf,
+    #[serde(skip_serializing)]
     repo: git2::Repository,
 }
 
-#[derive(RustcEncodable)]
-pub struct EncodableGitDatabase {
-    remote: GitRemote,
-    path: String,
-}
-
-impl Encodable for GitDatabase {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        EncodableGitDatabase {
-            remote: self.remote.clone(),
-            path: self.path.display().to_string()
-        }.encode(s)
-    }
-}
-
 /// GitCheckout is a local checkout of a particular revision. Calling
 /// `clone_into` with a reference will resolve the reference into a revision,
 /// and return a CargoError if no revision for that reference was found.
+#[derive(Serialize)]
 pub struct GitCheckout<'a> {
     database: &'a GitDatabase,
     location: PathBuf,
     revision: GitRevision,
+    #[serde(skip_serializing)]
     repo: git2::Repository,
 }
 
-#[derive(RustcEncodable)]
-pub struct EncodableGitCheckout {
-    database: EncodableGitDatabase,
-    location: String,
-    revision: String,
-}
-
-impl<'a> Encodable for GitCheckout<'a> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        EncodableGitCheckout {
-            location: self.location.display().to_string(),
-            revision: self.revision.to_string(),
-            database: EncodableGitDatabase {
-                remote: self.database.remote.clone(),
-                path: self.database.path.display().to_string(),
-            },
-        }.encode(s)
-    }
-}
-
 // Implementations
 
 impl GitRemote {
index fffdd5702c8e70c857ef7013a11cae37d5cbf2a1..bbd7e226ca7ef0ca80a1680ce0e24a7434a3d612 100644 (file)
@@ -3,7 +3,7 @@ use std::io::prelude::*;
 use std::fs::File;
 use std::path::Path;
 
-use rustc_serialize::json;
+use serde_json;
 
 use core::dependency::{Dependency, DependencyInner, Kind};
 use core::{SourceId, Summary, PackageId, Registry};
@@ -116,7 +116,7 @@ impl<'cfg> RegistryIndex<'cfg> {
                               -> CargoResult<(Summary, bool)> {
         let RegistryPackage {
             name, vers, cksum, deps, features, yanked
-        } = json::decode::<RegistryPackage>(line)?;
+        } = serde_json::from_str::<RegistryPackage>(line)?;
         let pkgid = PackageId::new(&name, &vers, &self.source_id)?;
         let deps: CargoResult<Vec<Dependency>> = deps.into_iter().map(|dep| {
             self.parse_registry_dependency(dep)
index 0f188a008708be05432084f53a22a20ffda852ad..2044c30ebfed50a37ced5f04c9666e30778e8e55 100644 (file)
@@ -184,7 +184,7 @@ pub struct RegistrySource<'cfg> {
     index_locked: bool,
 }
 
-#[derive(RustcDecodable)]
+#[derive(Deserialize)]
 pub struct RegistryConfig {
     /// Download endpoint for all crates. This will be appended with
     /// `/<crate>/<version>/download` and then will be hit with an HTTP GET
@@ -196,7 +196,7 @@ pub struct RegistryConfig {
     pub api: String,
 }
 
-#[derive(RustcDecodable)]
+#[derive(Deserialize)]
 struct RegistryPackage {
     name: String,
     vers: String,
@@ -206,7 +206,7 @@ struct RegistryPackage {
     yanked: Option<bool>,
 }
 
-#[derive(RustcDecodable)]
+#[derive(Deserialize)]
 struct RegistryDependency {
     name: String,
     req: String,
index e3c9b9c7b4146c4b04208df0e5fa02741a7843d9..67e60a074c930489bef02fbafc2882bd21c732c9 100644 (file)
@@ -5,7 +5,7 @@ use std::path::Path;
 use curl::easy::{Easy, List};
 use git2;
 use rustc_serialize::hex::ToHex;
-use rustc_serialize::json;
+use serde_json;
 use url::Url;
 
 use core::{PackageId, SourceId};
@@ -49,7 +49,7 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
                                            "the registry index")?;
         let path = lock.path().parent().unwrap();
         let contents = paths::read(&path.join("config.json"))?;
-        let config = json::decode(&contents)?;
+        let config = serde_json::from_str(&contents)?;
         Ok(Some(config))
     }
 
index abee238171371a529cbb1ef7e3ac36544064a69b..08af70451c87fadfa5585fc8fd2f65883abe9a89 100644 (file)
@@ -372,14 +372,13 @@ impl Config {
         walk_tree(&self.cwd, |mut file, path| {
             let mut contents = String::new();
             file.read_to_string(&mut contents)?;
-            let table = cargo_toml::parse(&contents,
-                                               path,
-                                               self).chain_error(|| {
+            let toml = cargo_toml::parse(&contents,
+                                         &path,
+                                         self).chain_error(|| {
                 human(format!("could not parse TOML configuration in `{}`",
                               path.display()))
             })?;
-            let toml = toml::Value::Table(table);
-            let value = CV::from_toml(path, toml).chain_error(|| {
+            let value = CV::from_toml(&path, toml).chain_error(|| {
                 human(format!("failed to load TOML configuration from `{}`",
                               path.display()))
             })?;
@@ -409,13 +408,13 @@ impl Config {
     }
 }
 
-#[derive(Eq, PartialEq, Clone, RustcEncodable, RustcDecodable, Copy)]
+#[derive(Eq, PartialEq, Clone, Copy)]
 pub enum Location {
     Project,
     Global
 }
 
-#[derive(Eq,PartialEq,Clone,RustcDecodable)]
+#[derive(Eq,PartialEq,Clone,Deserialize)]
 pub enum ConfigValue {
     Integer(i64, PathBuf),
     String(String, PathBuf),
@@ -743,9 +742,11 @@ pub fn set_config(cfg: &Config,
     let mut contents = String::new();
     let _ = file.read_to_string(&mut contents);
     let mut toml = cargo_toml::parse(&contents, file.path(), cfg)?;
-    toml.insert(key.to_string(), value.into_toml());
+    toml.as_table_mut()
+        .unwrap()
+        .insert(key.to_string(), value.into_toml());
 
-    let contents = toml::Value::Table(toml).to_string();
+    let contents = toml.to_string();
     file.seek(SeekFrom::Start(0))?;
     file.write_all(contents.as_bytes())?;
     file.file().set_len(contents.len() as u64)?;
index c7babd0b77f831c91976f637277ea24a2d07b0fc..14697ad8ea8ceda0b909c216889353f1a46777d2 100644 (file)
@@ -11,8 +11,8 @@ use std::string;
 use curl;
 use git2;
 use handlebars;
-use rustc_serialize::json;
 use semver;
+use serde_json;
 use term;
 use toml;
 use url;
@@ -334,13 +334,12 @@ from_error! {
     io::Error,
     ProcessError,
     git2::Error,
-    json::DecoderError,
-    json::EncoderError,
+    serde_json::Error,
     curl::Error,
     CliError,
-    toml::Error,
     url::ParseError,
-    toml::DecodeError,
+    toml::ser::Error,
+    toml::de::Error,
     ffi::NulError,
     term::Error,
     num::ParseIntError,
@@ -363,14 +362,17 @@ impl<E: CargoError> From<Human<E>> for Box<CargoError> {
 impl CargoError for semver::ReqParseError {}
 impl CargoError for io::Error {}
 impl CargoError for git2::Error {}
-impl CargoError for json::DecoderError {}
-impl CargoError for json::EncoderError {}
+impl CargoError for serde_json::Error {}
 impl CargoError for curl::Error {}
 impl CargoError for ProcessError {}
 impl CargoError for CargoTestError {}
 impl CargoError for CliError {}
-impl CargoError for toml::Error {}
-impl CargoError for toml::DecodeError {}
+impl CargoError for toml::ser::Error {
+    fn is_human(&self) -> bool { true }
+}
+impl CargoError for toml::de::Error {
+    fn is_human(&self) -> bool { true }
+}
 impl CargoError for url::ParseError {}
 impl CargoError for ffi::NulError {}
 impl CargoError for term::Error {}
index 64e6c35f1606ad797b03749fb5031bc225436b6a..9626494cd3d1c6b6a4415939f478071f18021ef1 100644 (file)
@@ -1,27 +1,23 @@
-use rustc_serialize::Encodable;
-use rustc_serialize::json::{self, Json};
+use serde::ser;
+use serde_json::{self, Value};
 
 use core::{PackageId, Target, Profile};
 
-pub trait Message: Encodable {
+pub trait Message: ser::Serialize {
     fn reason(&self) -> &str;
 }
 
 pub fn emit<T: Message>(t: T) {
-    let json = json::encode(&t).unwrap();
-    let mut map = match json.parse().unwrap() {
-        Json::Object(obj) => obj,
-        _ => panic!("not a json object"),
-    };
-    map.insert("reason".to_string(), Json::String(t.reason().to_string()));
-    println!("{}", Json::Object(map));
+    let mut json: Value = serde_json::to_value(&t).unwrap();
+    json["reason"] = json!(t.reason());
+    println!("{}", json);
 }
 
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 pub struct FromCompiler<'a> {
     pub package_id: &'a PackageId,
     pub target: &'a Target,
-    pub message: json::Json,
+    pub message: serde_json::Value,
 }
 
 impl<'a> Message for FromCompiler<'a> {
@@ -30,7 +26,7 @@ impl<'a> Message for FromCompiler<'a> {
     }
 }
 
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 pub struct Artifact<'a> {
     pub package_id: &'a PackageId,
     pub target: &'a Target,
@@ -45,7 +41,7 @@ impl<'a> Message for Artifact<'a> {
     }
 }
 
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 pub struct BuildScript<'a> {
     pub package_id: &'a PackageId,
     pub linked_libs: &'a [String],
index 8c06e30ca87952dcede25cab55522b1c134060d9..d44dafe56be472dca1d52c34c3aaeb9a27e3d0fc 100644 (file)
@@ -1,4 +1,4 @@
-use std::collections::{HashMap, HashSet};
+use std::collections::{HashMap, HashSet, BTreeSet};
 use std::default::Default;
 use std::fmt;
 use std::fs;
@@ -7,7 +7,8 @@ use std::str;
 
 use toml;
 use semver::{self, VersionReq};
-use rustc_serialize::{Decodable, Decoder};
+use serde::de::{self, Deserialize};
+use serde_ignored;
 
 use core::{SourceId, Profiles, PackageIdSpec, GitReference, WorkspaceConfig};
 use core::{Summary, Manifest, Target, Dependency, DependencyInner, PackageId};
@@ -29,7 +30,6 @@ pub struct Layout {
     examples: Vec<PathBuf>,
     tests: Vec<PathBuf>,
     benches: Vec<PathBuf>,
-
 }
 
 impl Layout {
@@ -102,15 +102,19 @@ pub fn to_manifest(contents: &str,
         None => manifest.clone(),
     };
     let root = parse(contents, &manifest, config)?;
-    let mut d = toml::Decoder::new(toml::Value::Table(root));
-    let manifest: TomlManifest = Decodable::decode(&mut d).map_err(|e| {
-        human(e.to_string())
+    let mut unused = BTreeSet::new();
+    let manifest: TomlManifest = serde_ignored::deserialize(root, |path| {
+        let mut key = String::new();
+        stringify(&mut key, &path);
+        if !key.starts_with("package.metadata") {
+            unused.insert(key);
+        }
     })?;
 
     return match manifest.to_real_manifest(source_id, &layout, config) {
         Ok((mut manifest, paths)) => {
-            if let Some(ref toml) = d.toml {
-                add_unused_keys(&mut manifest, toml, String::new());
+            for key in unused {
+                manifest.add_warning(format!("unused manifest key: {}", key));
             }
             if !manifest.targets().iter().any(|t| !t.is_custom_build()) {
                 bail!("no targets specified in the manifest\n  \
@@ -127,41 +131,43 @@ pub fn to_manifest(contents: &str,
         }
     };
 
-    fn add_unused_keys(m: &mut Manifest, toml: &toml::Value, key: String) {
-        if key == "package.metadata" {
-            return
-        }
-        match *toml {
-            toml::Value::Table(ref table) => {
-                for (k, v) in table.iter() {
-                    add_unused_keys(m, v, if key.is_empty() {
-                        k.clone()
-                    } else {
-                        key.clone() + "." + k
-                    })
+    fn stringify(dst: &mut String, path: &serde_ignored::Path) {
+        use serde_ignored::Path;
+
+        match *path {
+            Path::Root => {}
+            Path::Seq { parent, index } => {
+                stringify(dst, parent);
+                if dst.len() > 0 {
+                    dst.push_str(".");
                 }
+                dst.push_str(&index.to_string());
             }
-            toml::Value::Array(ref arr) => {
-                for v in arr.iter() {
-                    add_unused_keys(m, v, key.clone());
+            Path::Map { parent, ref key } => {
+                stringify(dst, parent);
+                if dst.len() > 0 {
+                    dst.push_str(".");
                 }
+                dst.push_str(key);
             }
-            _ => m.add_warning(format!("unused manifest key: {}", key)),
+            Path::Some { parent } |
+            Path::NewtypeVariant { parent } |
+            Path::NewtypeStruct { parent } => stringify(dst, parent),
         }
     }
 }
 
 pub fn parse(toml: &str,
              file: &Path,
-             config: &Config) -> CargoResult<toml::Table> {
-    let mut first_parser = toml::Parser::new(toml);
-    if let Some(toml) = first_parser.parse() {
-        return Ok(toml);
-    }
+             config: &Config) -> CargoResult<toml::Value> {
+    let first_error = match toml.parse() {
+        Ok(ret) => return Ok(ret),
+        Err(e) => e,
+    };
 
-    let mut second_parser = toml::Parser::new(toml);
+    let mut second_parser = toml::de::Deserializer::new(toml);
     second_parser.set_require_newline_after_table(false);
-    if let Some(toml) = second_parser.parse() {
+    if let Ok(ret) = toml::Value::deserialize(&mut second_parser) {
         let msg = format!("\
 TOML file found which contains invalid syntax and will soon not parse
 at `{}`.
@@ -171,25 +177,12 @@ invalid), but this file has a table header which does not have a newline after
 it. A newline needs to be added and this warning will soon become a hard error
 in the future.", file.display());
         config.shell().warn(&msg)?;
-        return Ok(toml)
+        return Ok(ret)
     }
 
-    let mut error_str = "could not parse input as TOML\n".to_string();
-    for error in first_parser.errors.iter() {
-        let (loline, locol) = first_parser.to_linecol(error.lo);
-        let (hiline, hicol) = first_parser.to_linecol(error.hi);
-        error_str.push_str(&format!("{}:{}:{}{} {}\n",
-                                    file.display(),
-                                    loline + 1, locol + 1,
-                                    if loline != hiline || locol != hicol {
-                                        format!("-{}:{}", hiline + 1,
-                                                hicol + 1)
-                                    } else {
-                                        "".to_string()
-                                    },
-                                    error.desc));
-    }
-    Err(human(error_str))
+    Err(first_error).chain_error(|| {
+        human("could not parse input as TOML")
+    })
 }
 
 type TomlLibTarget = TomlTarget;
@@ -198,14 +191,15 @@ type TomlExampleTarget = TomlTarget;
 type TomlTestTarget = TomlTarget;
 type TomlBenchTarget = TomlTarget;
 
-#[derive(RustcDecodable)]
+#[derive(Deserialize)]
+#[serde(untagged)]
 pub enum TomlDependency {
     Simple(String),
     Detailed(DetailedTomlDependency)
 }
 
 
-#[derive(RustcDecodable, Clone, Default)]
+#[derive(Deserialize, Clone, Default)]
 pub struct DetailedTomlDependency {
     version: Option<String>,
     path: Option<String>,
@@ -215,10 +209,11 @@ pub struct DetailedTomlDependency {
     rev: Option<String>,
     features: Option<Vec<String>>,
     optional: Option<bool>,
+    #[serde(rename = "default-features")]
     default_features: Option<bool>,
 }
 
-#[derive(RustcDecodable)]
+#[derive(Deserialize)]
 pub struct TomlManifest {
     package: Option<Box<TomlProject>>,
     project: Option<Box<TomlProject>>,
@@ -229,7 +224,9 @@ pub struct TomlManifest {
     test: Option<Vec<TomlTestTarget>>,
     bench: Option<Vec<TomlTestTarget>>,
     dependencies: Option<HashMap<String, TomlDependency>>,
+    #[serde(rename = "dev-dependencies")]
     dev_dependencies: Option<HashMap<String, TomlDependency>>,
+    #[serde(rename = "build-dependencies")]
     build_dependencies: Option<HashMap<String, TomlDependency>>,
     features: Option<HashMap<String, Vec<String>>>,
     target: Option<HashMap<String, TomlPlatform>>,
@@ -238,7 +235,7 @@ pub struct TomlManifest {
     badges: Option<HashMap<String, HashMap<String, String>>>,
 }
 
-#[derive(RustcDecodable, Clone, Default)]
+#[derive(Deserialize, Clone, Default)]
 pub struct TomlProfiles {
     test: Option<TomlProfile>,
     doc: Option<TomlProfile>,
@@ -250,50 +247,74 @@ pub struct TomlProfiles {
 #[derive(Clone)]
 pub struct TomlOptLevel(String);
 
-impl Decodable for TomlOptLevel {
-    fn decode<D: Decoder>(d: &mut D) -> Result<TomlOptLevel, D::Error> {
-        match d.read_u32() {
-            Ok(i) => Ok(TomlOptLevel(i.to_string())),
-            Err(_) => {
-                match d.read_str() {
-                    Ok(ref s) if s == "s" || s == "z" =>
-                        Ok(TomlOptLevel(s.to_string())),
-                    Ok(_) | Err(_) =>
-                        Err(d.error("expected an integer, a string \"z\" or a string \"s\""))
+impl de::Deserialize for TomlOptLevel {
+    fn deserialize<D>(d: D) -> Result<TomlOptLevel, D::Error>
+        where D: de::Deserializer
+    {
+        struct Visitor;
+
+        impl de::Visitor for Visitor {
+            type Value = TomlOptLevel;
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                formatter.write_str("an optimization level")
+            }
+
+            fn visit_i64<E>(self, value: i64) -> Result<TomlOptLevel, E>
+                where E: de::Error
+            {
+                Ok(TomlOptLevel(value.to_string()))
+            }
+
+            fn visit_str<E>(self, value: &str) -> Result<TomlOptLevel, E>
+                where E: de::Error
+            {
+                if value == "s" || value == "z" {
+                    Ok(TomlOptLevel(value.to_string()))
+                } else {
+                    Err(E::custom(format!("must be an integer, `z`, or `s`, \
+                                           but found: {}", value)))
                 }
             }
         }
+
+        d.deserialize_u32(Visitor)
     }
 }
 
-#[derive(RustcDecodable, Clone)]
+#[derive(Deserialize, Clone)]
+#[serde(untagged)]
 pub enum U32OrBool {
     U32(u32),
     Bool(bool),
 }
 
-#[derive(RustcDecodable, Clone, Default)]
+#[derive(Deserialize, Clone, Default)]
 pub struct TomlProfile {
+    #[serde(rename = "opt-level")]
     opt_level: Option<TomlOptLevel>,
     lto: Option<bool>,
+    #[serde(rename = "codegen-units")]
     codegen_units: Option<u32>,
     debug: Option<U32OrBool>,
+    #[serde(rename = "debug-assertions")]
     debug_assertions: Option<bool>,
     rpath: Option<bool>,
     panic: Option<String>,
 }
 
-#[derive(RustcDecodable, Clone, Debug)]
+#[derive(Deserialize, Clone, Debug)]
+#[serde(untagged)]
 pub enum StringOrBool {
     String(String),
     Bool(bool),
 }
 
-#[derive(RustcDecodable)]
+#[derive(Deserialize)]
 pub struct TomlProject {
     name: String,
     version: TomlVersion,
-    authors: Vec<String>,
+    authors: Option<Vec<String>>,
     build: Option<StringOrBool>,
     links: Option<String>,
     exclude: Option<Vec<String>>,
@@ -309,11 +330,12 @@ pub struct TomlProject {
     keywords: Option<Vec<String>>,
     categories: Option<Vec<String>>,
     license: Option<String>,
+    #[serde(rename = "license-file")]
     license_file: Option<String>,
     repository: Option<String>,
 }
 
-#[derive(RustcDecodable)]
+#[derive(Deserialize)]
 pub struct TomlWorkspace {
     members: Option<Vec<String>>,
 }
@@ -322,13 +344,30 @@ pub struct TomlVersion {
     version: semver::Version,
 }
 
-impl Decodable for TomlVersion {
-    fn decode<D: Decoder>(d: &mut D) -> Result<TomlVersion, D::Error> {
-        let s = d.read_str()?;
-        match s.to_semver() {
-            Ok(s) => Ok(TomlVersion { version: s }),
-            Err(e) => Err(d.error(&e)),
+impl de::Deserialize for TomlVersion {
+    fn deserialize<D>(d: D) -> Result<TomlVersion, D::Error>
+        where D: de::Deserializer
+    {
+        struct Visitor;
+
+        impl de::Visitor for Visitor {
+            type Value = TomlVersion;
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                formatter.write_str("a semver version")
+            }
+
+            fn visit_str<E>(self, value: &str) -> Result<TomlVersion, E>
+                where E: de::Error
+            {
+                match value.to_semver() {
+                    Ok(s) => Ok(TomlVersion { version: s}),
+                    Err(e) => Err(E::custom(e)),
+                }
+            }
         }
+
+        d.deserialize_str(Visitor)
     }
 }
 
@@ -630,7 +669,7 @@ impl TomlManifest {
             homepage: project.homepage.clone(),
             documentation: project.documentation.clone(),
             readme: project.readme.clone(),
-            authors: project.authors.clone(),
+            authors: project.authors.clone().unwrap_or(Vec::new()),
             license: project.license.clone(),
             license_file: project.license_file.clone(),
             repository: project.repository.clone(),
@@ -918,50 +957,50 @@ impl TomlDependency {
     }
 }
 
-#[derive(RustcDecodable, Debug, Clone)]
+#[derive(Default, Deserialize, Debug, Clone)]
 struct TomlTarget {
     name: Option<String>,
+
+    // The intention was to only accept `crate-type` here but historical
+    // versions of Cargo also accepted `crate_type`, so look for both.
+    #[serde(rename = "crate-type")]
     crate_type: Option<Vec<String>>,
+    #[serde(rename = "crate_type")]
+    crate_type2: Option<Vec<String>>,
+
     path: Option<PathValue>,
     test: Option<bool>,
     doctest: Option<bool>,
     bench: Option<bool>,
     doc: Option<bool>,
     plugin: Option<bool>,
+    #[serde(rename = "proc-macro")]
     proc_macro: Option<bool>,
     harness: Option<bool>,
+    #[serde(rename = "required-features")]
     required_features: Option<Vec<String>>,
 }
 
-#[derive(RustcDecodable, Clone)]
+#[derive(Deserialize, Clone)]
+#[serde(untagged)]
 enum PathValue {
     String(String),
     Path(PathBuf),
 }
 
 /// Corresponds to a `target` entry, but `TomlTarget` is already used.
-#[derive(RustcDecodable)]
+#[derive(Deserialize)]
 struct TomlPlatform {
     dependencies: Option<HashMap<String, TomlDependency>>,
+    #[serde(rename = "build-dependencies")]
     build_dependencies: Option<HashMap<String, TomlDependency>>,
+    #[serde(rename = "dev-dependencies")]
     dev_dependencies: Option<HashMap<String, TomlDependency>>,
 }
 
 impl TomlTarget {
     fn new() -> TomlTarget {
-        TomlTarget {
-            name: None,
-            crate_type: None,
-            path: None,
-            test: None,
-            doctest: None,
-            bench: None,
-            doc: None,
-            plugin: None,
-            proc_macro: None,
-            harness: None,
-            required_features: None
-        }
+        TomlTarget::default()
     }
 
     fn name(&self) -> String {
@@ -1100,7 +1139,8 @@ fn normalize(package_root: &Path,
         let path = l.path.clone().unwrap_or_else(
             || PathValue::Path(Path::new("src").join(&format!("{}.rs", l.name())))
         );
-        let crate_types = match l.crate_type.clone() {
+        let crate_types = l.crate_type.as_ref().or(l.crate_type2.as_ref());
+        let crate_types = match crate_types {
             Some(kinds) => kinds.iter().map(|s| LibKind::from_str(s)).collect(),
             None => {
                 vec![ if l.plugin == Some(true) {LibKind::Dylib}
@@ -1148,8 +1188,9 @@ fn normalize(package_root: &Path,
                 PathValue::Path(default(ex))
             });
 
-            let crate_types = match ex.crate_type {
-                Some(ref kinds) => kinds.iter().map(|s| LibKind::from_str(s)).collect(),
+            let crate_types = ex.crate_type.as_ref().or(ex.crate_type2.as_ref());
+            let crate_types = match crate_types {
+                Some(kinds) => kinds.iter().map(|s| LibKind::from_str(s)).collect(),
                 None => Vec::new()
             };
 
index 54a54e1dea09b75a2d734a96beae047112282a59..21db0467fe95bef8c2af75ce25dda696af2f98d8 100644 (file)
@@ -14,5 +14,7 @@ path = "lib.rs"
 
 [dependencies]
 curl = "0.4"
+serde = "0.9"
+serde_derive = "0.9"
+serde_json = "0.9"
 url = "1.0"
-rustc-serialize = "0.3"
index 915f44363a3bbd3c366628d7d5a3c07c73e2c64c..df032f349f2a52b4e3adbcc4f9363c7d4472b3d5 100644 (file)
@@ -1,6 +1,8 @@
 extern crate curl;
 extern crate url;
-extern crate rustc_serialize;
+extern crate serde_json;
+#[macro_use]
+extern crate serde_derive;
 
 use std::collections::HashMap;
 use std::fmt;
@@ -10,7 +12,6 @@ use std::io::{self, Cursor};
 use std::result;
 
 use curl::easy::{Easy, List};
-use rustc_serialize::json::{self, Json};
 
 use url::percent_encoding::{percent_encode, QUERY_ENCODE_SET};
 
@@ -37,26 +38,12 @@ pub enum Error {
     TokenMissing,
     Io(io::Error),
     NotFound,
-    JsonEncodeError(json::EncoderError),
-    JsonDecodeError(json::DecoderError),
-    JsonParseError(json::ParserError),
+    Json(serde_json::Error),
 }
 
-impl From<json::EncoderError> for Error {
-    fn from(err: json::EncoderError) -> Error {
-        Error::JsonEncodeError(err)
-    }
-}
-
-impl From<json::DecoderError> for Error {
-    fn from(err: json::DecoderError) -> Error {
-        Error::JsonDecodeError(err)
-    }
-}
-
-impl From<json::ParserError> for Error {
-    fn from(err: json::ParserError) -> Error {
-        Error::JsonParseError(err)
+impl From<serde_json::Error> for Error {
+    fn from(err: serde_json::Error) -> Error {
+        Error::Json(err)
     }
 }
 
@@ -66,14 +53,14 @@ impl From<curl::Error> for Error {
     }
 }
 
-#[derive(RustcDecodable)]
+#[derive(Deserialize)]
 pub struct Crate {
     pub name: String,
     pub description: Option<String>,
     pub max_version: String
 }
 
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 pub struct NewCrate {
     pub name: String,
     pub vers: String,
@@ -92,7 +79,7 @@ pub struct NewCrate {
     pub badges: HashMap<String, HashMap<String, String>>,
 }
 
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 pub struct NewCrateDependency {
     pub optional: bool,
     pub default_features: bool,
@@ -103,7 +90,7 @@ pub struct NewCrateDependency {
     pub kind: String,
 }
 
-#[derive(RustcDecodable)]
+#[derive(Deserialize)]
 pub struct User {
     pub id: u32,
     pub login: String,
@@ -117,13 +104,13 @@ pub struct Warnings {
     pub invalid_badges: Vec<String>,
 }
 
-#[derive(RustcDecodable)] struct R { ok: bool }
-#[derive(RustcDecodable)] struct ApiErrorList { errors: Vec<ApiError> }
-#[derive(RustcDecodable)] struct ApiError { detail: String }
-#[derive(RustcEncodable)] struct OwnersReq<'a> { users: &'a [&'a str] }
-#[derive(RustcDecodable)] struct Users { users: Vec<User> }
-#[derive(RustcDecodable)] struct TotalCrates { total: u32 }
-#[derive(RustcDecodable)] struct Crates { crates: Vec<Crate>, meta: TotalCrates }
+#[derive(Deserialize)] struct R { ok: bool }
+#[derive(Deserialize)] struct ApiErrorList { errors: Vec<ApiError> }
+#[derive(Deserialize)] struct ApiError { detail: String }
+#[derive(Serialize)] struct OwnersReq<'a> { users: &'a [&'a str] }
+#[derive(Deserialize)] struct Users { users: Vec<User> }
+#[derive(Deserialize)] struct TotalCrates { total: u32 }
+#[derive(Deserialize)] struct Crates { crates: Vec<Crate>, meta: TotalCrates }
 impl Registry {
     pub fn new(host: String, token: Option<String>) -> Registry {
         Registry::new_handle(host, token, Easy::new())
@@ -140,29 +127,29 @@ impl Registry {
     }
 
     pub fn add_owners(&mut self, krate: &str, owners: &[&str]) -> Result<()> {
-        let body = json::encode(&OwnersReq { users: owners })?;
+        let body = serde_json::to_string(&OwnersReq { users: owners })?;
         let body = self.put(format!("/crates/{}/owners", krate),
                                  body.as_bytes())?;
-        assert!(json::decode::<R>(&body)?.ok);
+        assert!(serde_json::from_str::<R>(&body)?.ok);
         Ok(())
     }
 
     pub fn remove_owners(&mut self, krate: &str, owners: &[&str]) -> Result<()> {
-        let body = json::encode(&OwnersReq { users: owners })?;
+        let body = serde_json::to_string(&OwnersReq { users: owners })?;
         let body = self.delete(format!("/crates/{}/owners", krate),
                                     Some(body.as_bytes()))?;
-        assert!(json::decode::<R>(&body)?.ok);
+        assert!(serde_json::from_str::<R>(&body)?.ok);
         Ok(())
     }
 
     pub fn list_owners(&mut self, krate: &str) -> Result<Vec<User>> {
         let body = self.get(format!("/crates/{}/owners", krate))?;
-        Ok(json::decode::<Users>(&body)?.users)
+        Ok(serde_json::from_str::<Users>(&body)?.users)
     }
 
     pub fn publish(&mut self, krate: &NewCrate, tarball: &File)
                    -> Result<Warnings> {
-        let json = json::encode(krate)?;
+        let json = serde_json::to_string(krate)?;
         // Prepare the body. The format of the upload request is:
         //
         //      <le u32 of json>
@@ -208,28 +195,27 @@ impl Registry {
             body.read(buf).unwrap_or(0)
         })?;
 
-        // Can't derive RustcDecodable because JSON has a key named "crate" :(
         let response = if body.len() > 0 {
-            Json::from_str(&body)?
+            body.parse::<serde_json::Value>()?
         } else {
-            Json::from_str("{}")?
+            "{}".parse()?
         };
 
         let invalid_categories: Vec<String> =
-            response
-                .find_path(&["warnings", "invalid_categories"])
-                .and_then(Json::as_array)
+            response.get("warnings")
+                .and_then(|j| j.get("invalid_categories"))
+                .and_then(|j| j.as_array())
                 .map(|x| {
-                    x.iter().flat_map(Json::as_string).map(Into::into).collect()
+                    x.iter().flat_map(|j| j.as_str()).map(Into::into).collect()
                 })
                 .unwrap_or_else(Vec::new);
 
         let invalid_badges: Vec<String> =
-            response
-                .find_path(&["warnings", "invalid_badges"])
-                .and_then(Json::as_array)
+            response.get("warnings")
+                .and_then(|j| j.get("invalid_badges"))
+                .and_then(|j| j.as_array())
                 .map(|x| {
-                    x.iter().flat_map(Json::as_string).map(Into::into).collect()
+                    x.iter().flat_map(|j| j.as_str()).map(Into::into).collect()
                 })
                 .unwrap_or_else(Vec::new);
 
@@ -246,21 +232,21 @@ impl Registry {
             None, Auth::Unauthorized
         )?;
 
-        let crates = json::decode::<Crates>(&body)?;
+        let crates = serde_json::from_str::<Crates>(&body)?;
         Ok((crates.crates, crates.meta.total))
     }
 
     pub fn yank(&mut self, krate: &str, version: &str) -> Result<()> {
         let body = self.delete(format!("/crates/{}/{}/yank", krate, version),
                                     None)?;
-        assert!(json::decode::<R>(&body)?.ok);
+        assert!(serde_json::from_str::<R>(&body)?.ok);
         Ok(())
     }
 
     pub fn unyank(&mut self, krate: &str, version: &str) -> Result<()> {
         let body = self.put(format!("/crates/{}/{}/unyank", krate, version),
                                  &[])?;
-        assert!(json::decode::<R>(&body)?.ok);
+        assert!(serde_json::from_str::<R>(&body)?.ok);
         Ok(())
     }
 
@@ -337,7 +323,7 @@ fn handle(handle: &mut Easy,
         Ok(body) => body,
         Err(..) => return Err(Error::NonUtf8Body),
     };
-    match json::decode::<ApiErrorList>(&body) {
+    match serde_json::from_str::<ApiErrorList>(&body) {
         Ok(errors) => {
             return Err(Error::Api(errors.errors.into_iter().map(|s| s.detail)
                                         .collect()))
@@ -369,9 +355,7 @@ impl fmt::Display for Error {
             Error::TokenMissing => write!(f, "no upload token found, please run `cargo login`"),
             Error::Io(ref e) => write!(f, "io error: {}", e),
             Error::NotFound => write!(f, "cannot find crate"),
-            Error::JsonEncodeError(ref e) => write!(f, "json encode error: {}", e),
-            Error::JsonDecodeError(ref e) => write!(f, "json decode error: {}", e),
-            Error::JsonParseError(ref e) => write!(f, "json parse error: {}", e),
+            Error::Json(ref e) => write!(f, "json error: {}", e),
         }
     }
 }
index 63aae50dfa4763f2d551388b8072c8074085aeb1..9db8606d86c86df7e4e8ec5ca136fad3547880f6 100644 (file)
@@ -206,12 +206,13 @@ fn invalid_global_config() {
 [ERROR] Couldn't load Cargo configuration
 
 Caused by:
-  could not parse TOML configuration in `[..]config`
+  could not parse TOML configuration in `[..]`
 
 Caused by:
   could not parse input as TOML
-[..]config:1:2 expected `=`, but found eof
 
+Caused by:
+  expected an equals, found eof at line 1
 "));
 }
 
@@ -232,7 +233,7 @@ fn bad_cargo_lock() {
 [ERROR] failed to parse lock file at: [..]Cargo.lock
 
 Caused by:
-  expected a value of type `string` for the key `package.name`
+  missing field `name` for key `package`
 "));
 }
 
@@ -315,7 +316,7 @@ fn bad_source_in_cargo_lock() {
 [ERROR] failed to parse lock file at: [..]
 
 Caused by:
-  invalid source `You shall not parse` for the key `package.source`
+  invalid source `You shall not parse` for key `package.source`
 "));
 }
 
@@ -421,8 +422,9 @@ fn malformed_override() {
 
 Caused by:
   could not parse input as TOML
-Cargo.toml:[..]
 
+Caused by:
+  expected a table key, found a newline at line 8
 "));
 }
 
index 721ec3478b75cf00972b4f870207d755e1b8daa1..c937f0487e455418ef367c13fff86bc999f2d55a 100644 (file)
@@ -100,8 +100,9 @@ fn cargo_compile_with_invalid_manifest2() {
 
 Caused by:
   could not parse input as TOML
-Cargo.toml:3:19-3:20 expected a value
 
+Caused by:
+  invalid number at line 3
 "))
 }
 
@@ -124,8 +125,11 @@ fn cargo_compile_with_invalid_manifest3() {
 [ERROR] failed to parse manifest at `[..]`
 
 Caused by:
-  could not parse input as TOML\n\
-src[/]Cargo.toml:1:5-1:6 expected a value\n\n"))
+  could not parse input as TOML
+
+Caused by:
+  invalid number at line 1
+"))
 }
 
 #[test]
@@ -175,7 +179,7 @@ fn cargo_compile_with_invalid_version() {
 [ERROR] failed to parse manifest at `[..]`
 
 Caused by:
-  cannot parse '1.0' as a semver for the key `project.version`
+  cannot parse '1.0' as a semver for key `project.version`
 "))
 
 }
@@ -876,39 +880,39 @@ suffix = env::consts::DLL_SUFFIX,
 fn crate_env_vars() {
     let p = project("foo")
         .file("Cargo.toml", r#"
-           [project]
-           name = "foo"
-           version = "0.5.1-alpha.1"
-           description = "This is foo"
-           homepage = "http://example.com"
-           authors = ["wycats@example.com"]
+        [project]
+        name = "foo"
+        version = "0.5.1-alpha.1"
+        description = "This is foo"
+        homepage = "http://example.com"
+        authors = ["wycats@example.com"]
         "#)
         .file("src/main.rs", r#"
             extern crate foo;
 
 
-           static VERSION_MAJOR: &'static str = env!("CARGO_PKG_VERSION_MAJOR");
-           static VERSION_MINOR: &'static str = env!("CARGO_PKG_VERSION_MINOR");
-           static VERSION_PATCH: &'static str = env!("CARGO_PKG_VERSION_PATCH");
-           static VERSION_PRE: &'static str = env!("CARGO_PKG_VERSION_PRE");
-           static VERSION: &'static str = env!("CARGO_PKG_VERSION");
-           static CARGO_MANIFEST_DIR: &'static str = env!("CARGO_MANIFEST_DIR");
-           static PKG_NAME: &'static str = env!("CARGO_PKG_NAME");
-           static HOMEPAGE: &'static str = env!("CARGO_PKG_HOMEPAGE");
-           static DESCRIPTION: &'static str = env!("CARGO_PKG_DESCRIPTION");
+            static VERSION_MAJOR: &'static str = env!("CARGO_PKG_VERSION_MAJOR");
+            static VERSION_MINOR: &'static str = env!("CARGO_PKG_VERSION_MINOR");
+            static VERSION_PATCH: &'static str = env!("CARGO_PKG_VERSION_PATCH");
+            static VERSION_PRE: &'static str = env!("CARGO_PKG_VERSION_PRE");
+            static VERSION: &'static str = env!("CARGO_PKG_VERSION");
+            static CARGO_MANIFEST_DIR: &'static str = env!("CARGO_MANIFEST_DIR");
+            static PKG_NAME: &'static str = env!("CARGO_PKG_NAME");
+            static HOMEPAGE: &'static str = env!("CARGO_PKG_HOMEPAGE");
+            static DESCRIPTION: &'static str = env!("CARGO_PKG_DESCRIPTION");
 
             fn main() {
                 let s = format!("{}-{}-{} @ {} in {}", VERSION_MAJOR,
                                 VERSION_MINOR, VERSION_PATCH, VERSION_PRE,
                                 CARGO_MANIFEST_DIR);
-                assert_eq!(s, foo::version());
-                println!("{}", s);
-                assert_eq!("foo", PKG_NAME);
-                assert_eq!("http://example.com", HOMEPAGE);
-                assert_eq!("This is foo", DESCRIPTION);
+                 assert_eq!(s, foo::version());
+                 println!("{}", s);
+                 assert_eq!("foo", PKG_NAME);
+                 assert_eq!("http://example.com", HOMEPAGE);
+                 assert_eq!("This is foo", DESCRIPTION);
                 let s = format!("{}.{}.{}-{}", VERSION_MAJOR,
                                 VERSION_MINOR, VERSION_PATCH, VERSION_PRE);
-                assert_eq!(s, VERSION);
+                assert_eq!(s, VERSION);
             }
         "#)
         .file("src/lib.rs", r#"
@@ -1755,8 +1759,9 @@ Caused by:
 
 Caused by:
   could not parse input as TOML
-[..].cargo[..]config:2:20-2:21 expected `=`, but found `i`
 
+Caused by:
+  expected an equals, found an identifier at line 2
 "));
 }
 
index 55ef9643f1b5473f31892087fb11572a32a5e449..233a378d3ee616f2acb4d39512215f1958e90d4e 100644 (file)
@@ -17,6 +17,8 @@ kernel32-sys = "0.2"
 libc = "0.2"
 log = "0.3"
 rustc-serialize = "0.3"
+serde = "0.9"
+serde_json = "0.9"
 tar = { version = "0.4", default-features = false }
 tempdir = "0.3"
 term = "0.4.4"
index affb786379543190a1dce444633f87436ebdde94..11df25fdd1363c26d996b60929a418cd86dd4cf3 100644 (file)
@@ -8,6 +8,9 @@ extern crate git2;
 extern crate hamcrest;
 extern crate libc;
 extern crate rustc_serialize;
+extern crate serde;
+#[macro_use]
+extern crate serde_json;
 extern crate tar;
 extern crate tempdir;
 extern crate term;
@@ -49,6 +52,7 @@ fn _process(t: &OsStr) -> cargo::util::ProcessBuilder {
      .env("CARGO_HOME", support::paths::home().join(".cargo"))
      .env_remove("RUSTC")
      .env_remove("RUSTFLAGS")
+     .env_remove("CARGO_INCREMENTAL")
      .env_remove("XDG_CONFIG_HOME")      // see #2345
      .env("GIT_CONFIG_NOSYSTEM", "1")    // keep trying to sandbox ourselves
      .env_remove("CARGO_TARGET_DIR")     // we assume 'target'
index ecc3e017de68bea6db1daeef338d96271954c4ae..88b5c39643781e3c2296c730608340438b93c42a 100644 (file)
@@ -11,7 +11,7 @@ use std::process::Output;
 use std::str;
 use std::usize;
 
-use rustc_serialize::json::Json;
+use serde_json::{self, Value};
 use url::Url;
 use hamcrest as ham;
 use cargo::util::ProcessBuilder;
@@ -335,7 +335,7 @@ pub struct Execs {
     expect_stderr_contains: Vec<String>,
     expect_stdout_not_contains: Vec<String>,
     expect_stderr_not_contains: Vec<String>,
-    expect_json: Option<Vec<Json>>,
+    expect_json: Option<Vec<Value>>,
 }
 
 impl Execs {
@@ -376,7 +376,7 @@ impl Execs {
 
     pub fn with_json(mut self, expected: &str) -> Execs {
         self.expect_json = Some(expected.split("\n\n").map(|obj| {
-            Json::from_str(obj).unwrap()
+            obj.parse().unwrap()
         }).collect());
         self
     }
@@ -500,8 +500,8 @@ impl Execs {
         }
     }
 
-    fn match_json(&self, expected: &Json, line: &str) -> ham::MatchResult {
-        let actual = match Json::from_str(line) {
+    fn match_json(&self, expected: &Value, line: &str) -> ham::MatchResult {
+        let actual = match line.parse() {
              Err(e) => return Err(format!("invalid json, {}:\n`{}`", e, line)),
              Ok(actual) => actual,
         };
@@ -509,8 +509,10 @@ impl Execs {
         match find_mismatch(expected, &actual) {
             Some((expected_part, actual_part)) => Err(format!(
                 "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
-                expected.pretty(), actual.pretty(),
-                expected_part.pretty(), actual_part.pretty()
+                serde_json::to_string_pretty(expected).unwrap(),
+                serde_json::to_string_pretty(&actual).unwrap(),
+                serde_json::to_string_pretty(expected_part).unwrap(),
+                serde_json::to_string_pretty(actual_part).unwrap(),
             )),
             None => Ok(()),
         }
@@ -583,32 +585,42 @@ fn lines_match_works() {
 }
 
 // Compares JSON object for approximate equality.
-// You can use `[..]` wildcard in strings (useful for OS dependent things such as paths).
-// You can use a `"{...}"` string literal as a wildcard for arbitrary nested JSON (useful
-// for parts of object emitted by other programs (e.g. rustc) rather than Cargo itself).
-// Arrays are sorted before comparison.
-fn find_mismatch<'a>(expected: &'a Json, actual: &'a Json) -> Option<(&'a Json, &'a Json)> {
-    use rustc_serialize::json::Json::*;
+// You can use `[..]` wildcard in strings (useful for OS dependent things such
+// as paths).  You can use a `"{...}"` string literal as a wildcard for
+// arbitrary nested JSON (useful for parts of object emitted by other programs
+// (e.g. rustc) rather than Cargo itself).  Arrays are sorted before comparison.
+fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value)
+                     -> Option<(&'a Value, &'a Value)> {
+    use serde_json::Value::*;
     match (expected, actual) {
-        (&I64(l), &I64(r)) if l == r => None,
-        (&F64(l), &F64(r)) if l == r => None,
-        (&U64(l), &U64(r)) if l == r => None,
-        (&Boolean(l), &Boolean(r)) if l == r => None,
+        (&Number(ref l), &Number(ref r)) if l == r => None,
+        (&Bool(l), &Bool(r)) if l == r => None,
         (&String(ref l), &String(ref r)) if lines_match(l, r) => None,
         (&Array(ref l), &Array(ref r)) => {
             if l.len() != r.len() {
                 return Some((expected, actual));
             }
 
-            fn sorted(xs: &Vec<Json>) -> Vec<&Json> {
-                let mut result = xs.iter().collect::<Vec<_>>();
-                result.sort_by(|x, y| x.partial_cmp(y).expect("JSON spec does not allow NaNs"));
-                result
-            }
+            let mut l = l.iter().collect::<Vec<_>>();
+            let mut r = r.iter().collect::<Vec<_>>();
 
-            sorted(l).iter().zip(sorted(r))
-             .filter_map(|(l, r)| find_mismatch(l, r))
-             .nth(0)
+            l.retain(|l| {
+                match r.iter().position(|r| find_mismatch(l, r).is_none()) {
+                    Some(i) => {
+                        r.remove(i);
+                        false
+                    }
+                    None => true
+                }
+            });
+
+            if l.len() > 0 {
+                assert!(r.len() > 0);
+                Some((&l[0], &r[0]))
+            } else {
+                assert!(r.len() == 0);
+                None
+            }
         }
         (&Object(ref l), &Object(ref r)) => {
             let same_keys = l.len() == r.len() && l.keys().all(|k| r.contains_key(k));
index a57dfa2632754259d02f736dfa2ad1ec7888cd0a..3eae943299217dc13fc310dfdbda59fc54849133 100644 (file)
@@ -7,7 +7,6 @@ use flate2::Compression::Default;
 use flate2::write::GzEncoder;
 use git2;
 use rustc_serialize::hex::ToHex;
-use rustc_serialize::json::ToJson;
 use tar::{Builder, Header};
 use url::Url;
 
@@ -137,29 +136,29 @@ impl Package {
 
         // Figure out what we're going to write into the index
         let deps = self.deps.iter().map(|dep| {
-            let mut map = HashMap::new();
-            map.insert("name".to_string(), dep.name.to_json());
-            map.insert("req".to_string(), dep.vers.to_json());
-            map.insert("features".to_string(), dep.features.to_json());
-            map.insert("default_features".to_string(), true.to_json());
-            map.insert("target".to_string(), dep.target.to_json());
-            map.insert("optional".to_string(), false.to_json());
-            map.insert("kind".to_string(), dep.kind.to_json());
-            map
+            json!({
+                "name": dep.name,
+                "req": dep.vers,
+                "features": dep.features,
+                "default_features": true,
+                "target": dep.target,
+                "optional": false,
+                "kind": dep.kind,
+            })
         }).collect::<Vec<_>>();
         let cksum = {
             let mut c = Vec::new();
             t!(t!(File::open(&self.archive_dst())).read_to_end(&mut c));
             cksum(&c)
         };
-        let mut dep = HashMap::new();
-        dep.insert("name".to_string(), self.name.to_json());
-        dep.insert("vers".to_string(), self.vers.to_json());
-        dep.insert("deps".to_string(), deps.to_json());
-        dep.insert("cksum".to_string(), cksum.to_json());
-        dep.insert("features".to_string(), self.features.to_json());
-        dep.insert("yanked".to_string(), self.yanked.to_json());
-        let line = dep.to_json().to_string();
+        let line = json!({
+            "name": self.name,
+            "vers": self.vers,
+            "deps": deps,
+            "cksum": cksum,
+            "features": self.features,
+            "yanked": self.yanked,
+        }).to_string();
 
         let file = match self.name.len() {
             1 => format!("1/{}", self.name),
index c84d28cdd6b8d9b11be20b01ca37dabc39874a27..1a60826cd2f790a89deb157f66447ec3517c56b7 100644 (file)
@@ -1317,17 +1317,17 @@ fn old_version_req_upstream() {
     p.build();
 
     Package::new("remote", "0.3.0")
-                       .file("Cargo.toml", r#"
-                               [project]
+            .file("Cargo.toml", r#"
+                [project]
                 name = "remote"
                 version = "0.3.0"
                 authors = []
 
                 [dependencies]
                 bar = "0.2*"
-                       "#)
+            "#)
             .file("src/lib.rs", "")
-                       .publish();
+            .publish();
     Package::new("bar", "0.2.0").publish();
 
     assert_that(p.cargo("build"),
@@ -1356,17 +1356,17 @@ fn toml_lies_but_index_is_truth() {
     Package::new("foo", "0.2.0").publish();
     Package::new("bar", "0.3.0")
             .dep("foo", "0.2.0")
-                       .file("Cargo.toml", r#"
-                               [project]
+            .file("Cargo.toml", r#"
+                [project]
                 name = "bar"
                 version = "0.3.0"
                 authors = []
 
                 [dependencies]
                 foo = "0.1.0"
-                       "#)
+            "#)
             .file("src/lib.rs", "extern crate foo;")
-                       .publish();
+            .publish();
 
     let p = project("foo")
         .file("Cargo.toml", r#"